package com.usefullc.system.service.interceptor;

import com.usefullc.common.constants.SystemConstant;
import com.usefullc.common.exception.BizException;
import com.usefullc.common.util.RequestUtils;
import com.usefullc.common.util.ResponseUtils;
import com.usefullc.system.validator.UsefulValid;
import com.usefullc.system.controller.ResponseExceptionHandler;
import com.usefullc.system.entity.WebResult;
import com.usefullc.system.service.component.LocalComponent;
import com.usefullc.system.service.component.SystemConfigComponent;
import com.usefullc.system.service.component.extend.ExtendDataComponent;
import com.usefullc.system.validator.UsefulValidator;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.List;

/**
 * @author: Sampson
 * @date: 2018-12-20 14:56
 */
@Aspect
@Component
public class SystemAspect {

    Logger logger = LoggerFactory.getLogger(SystemAspect.class);
    Logger bizLogger = LoggerFactory.getLogger("biz");

    @Autowired
    private ResponseExceptionHandler responseExceptionHandler;
    @Autowired
    private LocalComponent localComponent;

    @Autowired
    private SystemConfigComponent systemConfigComponent;


    @Autowired
    private List<AspectProcess> aspectProcessList;


    @Autowired
    private ExtendDataComponent dictComponent;

    @Value("${usefullc.api.host}")
    private String currentHttpUrl;

    @Around("@annotation(org.springframework.web.bind.annotation.GetMapping) ||" +
            "@annotation(org.springframework.web.bind.annotation.PostMapping)"
    )
    public Object controllerMethodCall(ProceedingJoinPoint joinPoint) {
        Object proceed;
        HttpServletRequest request = null;
        try {
            //请求参数校验
            Method targetMethod = ((MethodSignature) (joinPoint.getSignature())).getMethod();
            Parameter[] parameters = targetMethod.getParameters();
            for (int i = 0; i < parameters.length; i++) {
                Parameter parameter = parameters[0];
                if(parameter.isAnnotationPresent(UsefulValid.class)){
                    UsefulValid usefulValid = parameter.getAnnotation(UsefulValid.class);
                    Object requestParam = joinPoint.getArgs()[i];
                    UsefulValidator.validator(requestParam,usefulValid);
                }
            }
            //end
            request = RequestUtils.getRequest();

            //业务拦截实现处理
            for (AspectProcess aspectProcess : aspectProcessList) {
                aspectProcess.process(joinPoint,request);
            }


            proceed = joinPoint.proceed();
            if (proceed instanceof WebResult) {
                WebResult webResult = (WebResult) proceed;
                // prod print
//                if (systemConfigComponent.isProd()) {
//                    webResult.setData("");
//                }
                localChanged(webResult);

                //处理字典数据，针对请求接口是否要处理
                proceed = dictComponent.wrapperWebResult(webResult);
            }

        } catch (Throwable t) {
////            HttpServletResponse response = ResponseUtils.getResponse();
////            try {
////                request.getRequestDispatcher("/error").forward(request,response);
////            } catch (Exception e) {
////                e.printStackTrace();
////            }
//            throw new  RuntimeException(t);
//            request.setAttribute(HandlerMapping.PRODUCIBLE_MEDIA_TYPES_ATTRIBUTE,"application/json");
//            throw new RuntimeException(t);
            HttpServletResponse response = ResponseUtils.getResponse();
//            response.setContentType("application/json;charset=utf-8");
//            response.setHeader("Content-type","application/json;charset=utf-8");
            //遇到异常
            WebResult webResult = new WebResult(false, SystemConstant.ResponseCode.SYSTEM_ERROR);
            //业务中异常
            boolean errorTrace = true;
            if (t instanceof BizException) {
                BizException bizException = (BizException) t;
                errorTrace = bizException.isErrorTrace();
                webResult.setMessage(bizException.getMessage());
                webResult.setCode(bizException.getCode());
                //not prod print
                if (!systemConfigComponent.isProd()) {
                    webResult.setData(bizException.getData());
                }
                //返回http status 的场景
                if(bizException.getHttpStatus() != HttpStatus.OK.value()){
                    String redirectUrl =  "redirectHttpStatus?httpStatus="+bizException.getHttpStatus();
                    response.setHeader("Location",currentHttpUrl+"/"+redirectUrl);
                }
                //未预知异常
            } else {
                //index 唯一索引消息处理
//                if (t.getCause() instanceof ConstraintViolationException) {
//                    String constraintName = ((ConstraintViolationException) t.getCause()).getClass().getName();
//                    webResult.setMessage("${" + constraintName + "}");
//                } else {
//                    webResult.setMessage(t.getMessage());
//                }
                //not prod print
                if (!systemConfigComponent.isProd()) {
                    webResult.setData(ExceptionUtils.getStackTrace(t));
                }
            }
            localChanged(webResult);

            if(errorTrace){
                logger.error(ExceptionUtils.getStackTrace(t));
            }
            return webResult;



//            return responseExceptionHandler.exceptionHandler(request,t);
        } finally {
            try{
                for (AspectProcess aspectProcess : aspectProcessList) {
                    aspectProcess.clean();
                }
            }catch (Exception e){
               logger.error("clean failed",e);
            }
        }
        return proceed;
    }

    private void localChanged(WebResult webResult) {
        String message = webResult.getMessage();
        if (StringUtils.isNotEmpty(message)) {
            if (message.trim().startsWith("${") && message.endsWith("}")) {
                String key = message.substring(2, message.length() - 1);
                String languageText = localComponent.getLanguageText(RequestUtils.getRequest(), key);
                webResult.setMessage(languageText);
            }
        }else{
            if(webResult.isSuccess()){
                webResult.setMessage("操作成功");
            }else{
                webResult.setMessage("操作失败");
            }
        }
    }


}
